package com.yourenbang.lingyun.transaction.web.service.impl.pay.transaction;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yourenbang.lingyun.constants.BizCodeMessages;
import com.yourenbang.lingyun.constants.enums.ChannelIdEnums;
import com.yourenbang.lingyun.constants.enums.PlatNoEnums;
import com.yourenbang.lingyun.constants.enums.PolicyEnum;
import com.yourenbang.lingyun.constants.enums.pay.PayFromEnum;
import com.yourenbang.lingyun.constants.enums.pay.PayTypeEnum;
import com.yourenbang.lingyun.constants.enums.table.PayTransactionEnum;
import com.yourenbang.lingyun.core.exception.UserBizException;
import com.yourenbang.lingyun.core.util.KLog;
import com.yourenbang.lingyun.core.util.StringUtils;
import com.yourenbang.lingyun.core.util.date.DateFormat;
import com.yourenbang.lingyun.core.util.date.LocalDateUtils;
import com.yourenbang.lingyun.core.util.encrypt.dy.*;
import com.yourenbang.lingyun.domain.Merchant21;
import com.yourenbang.lingyun.domain.Terminal21;
import com.yourenbang.lingyun.domain.Terminal21Example;
import com.yourenbang.lingyun.mapper.Merchant21Mapper;
import com.yourenbang.lingyun.mapper.Terminal21Mapper;
import com.yourenbang.lingyun.transaction.config.AcmTransactionParams;
import com.yourenbang.lingyun.transaction.constant.LklTransTypeEnum;
import com.yourenbang.lingyun.transaction.web.domain.vo.pay.dy.DyTransactionVO;
import com.yourenbang.lingyun.transaction.web.service.PayTransactionFormatService;
import com.yourenbang.merchant.api.service.yxy.MerchantYxyApiService;
import com.yourenbang.terminal.api.service.RpcYxyTerminalService;
import com.yourenbang.transaction.api.model.vo.pay.PayTransaction;
import com.yourenbang.transaction.api.service.pay.PayTypeApiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @Description 电银
 * @Date 2021/5/25 11:00
 * @Created by Jason
 */
@Service
@Slf4j
public class DyPayTransactionFormatServiceImpl implements PayTransactionFormatService {
    @Autowired
    PayTypeApiService payTypeApiService;
    @Autowired
    AcmTransactionParams acmTransactionParams;
    @Autowired
    private RpcYxyTerminalService rpcYxyTerminalService;
    @Autowired
    private MerchantYxyApiService merchantYxyApiService;
    @Autowired
    private Merchant21Mapper merchant21Mapper;
    @Autowired
    private Terminal21Mapper terminal21Mapper;

    @Override
    public PayTransaction payTransactionFormat(JSONObject jsonObject) {
        KLog.info("电银格式化交易推送入参:{}",jsonObject.toJSONString());
        DyTransactionVO dyTransactionVO = jsonObject.toJavaObject(DyTransactionVO.class);
        PayTransaction payTransaction = new PayTransaction();

        payTransaction.setMerchantNo(dyTransactionVO.getMERC_ID());
        payTransaction.setMerchantName(dyTransactionVO.getMERC_NM());

//        payTransaction.setRealName();

        payTransaction.setOrderNo(dyTransactionVO.getLOG_NO());
        payTransaction.setTransactionNo(dyTransactionVO.getLOG_NO());
        payTransaction.setSysRef((dyTransactionVO.getSREF_NO()));
//        payTransaction.setSid();
//        payTransaction.setRevokeSid("");
        payTransaction.setTransactionAmount(new BigDecimal(dyTransactionVO.getTXN_AMT()));
        if (StringUtils.isNotBlank(dyTransactionVO.getFEE_ORG_NO())) {
            payTransaction.setTransactionFee(new BigDecimal(dyTransactionVO.getFEE_ORG_NO()));
        }


        payTransaction.setCardFlag(formatCardFlagDy(dyTransactionVO.getCRD_FLG(),dyTransactionVO.getTXN_CD()));
        payTransaction.setTerminalId(dyTransactionVO.getTRM_NO());
//        payTransaction.setPsamNo("");
        payTransaction.setSn(dyTransactionVO.getSN_NO());
 //       payTransaction.setTransactionCardNo();
//        payTransaction.setTransactionBank("");
        payTransaction.setTransactionCardType(formatCardFlagDy(dyTransactionVO.getCRD_FLG(),dyTransactionVO.getTXN_CD()));
//        payTransaction.setSettlementCardNo("");
//        payTransaction.setSettlementBank("");
//        payTransaction.setSettlementCardType("");
        payTransaction.setStatus(formatTradeStatus(dyTransactionVO.getTXN_STS()));
        LocalDateTime transTime = LocalDateTime.now();
        if (StringUtils.isNotBlank(dyTransactionVO.getTXN_TM())) {
             transTime = LocalDateUtils.stringToLocalDateTime
                    (dyTransactionVO.getTXN_TM(), DateFormat.DATETIME_COMPACT.getPartten());
        }
        payTransaction.setTransactionTime(transTime);
        payTransaction.setTransactionMonth(
                LocalDateUtils.localDateTimeByFormat(transTime, DateFormat.DATE_MONTH.getPartten()));
        payTransaction.setTransactionDay(LocalDateUtils.localDateTimeByFormat(transTime, DateFormat.DATE_COMPACT.getPartten()));

//        payTransaction.setFrontSuccessTime(LocalDateTime.now());
//        payTransaction.setProvinceCode("");
//        payTransaction.setCityCode("");
//        payTransaction.setDistrictCode("");
//        payTransaction.setLongitude("");
//        payTransaction.setLatitude("");
//        payTransaction.setAreaCode("");

//        payTransaction.setWithdrawalOrderNo("");
//        payTransaction.setWithdrawalTransactionNo("");
//        payTransaction.setWithdrawalAmount(new BigDecimal("0"));
        if (StringUtils.isNotBlank(dyTransactionVO.getSEP_NUM())) {
            payTransaction.setWithdrawalFee(new BigDecimal(dyTransactionVO.getSEP_NUM()));
        }
        if (StringUtils.isNotBlank(dyTransactionVO.getFEE_ORG_NO())) {
            payTransaction.setFeeAmt(new BigDecimal(dyTransactionVO.getFEE_ORG_NO()));
        }
//        payTransaction.setAccAmt(new BigDecimal("0"));
//        payTransaction.setWithdrawalQueryTime(LocalDateTime.now());
//        payTransaction.setWithdrawalQueryCount(0);
//        payTransaction.setWithdrawalDrawTime(LocalDateTime.now());
//        payTransaction.setWithdrawalDrawCount(0);
        payTransaction.setWithdrawalStatus(PayTransactionEnum.WithdrawalStatusEnum.STATUS_40.getCode());

        Terminal21Example terminal21Example=new Terminal21Example();
        terminal21Example.createCriteria().andTerminalSnLike("%" + payTransaction.getSn()).andChannelIdIn(Arrays.asList(ChannelIdEnums.yxy_dy_d40.getCode(),
                ChannelIdEnums.yxy_dy_d45.getCode(), ChannelIdEnums.YXY_DY_D50.getCode(), ChannelIdEnums.YXY_DY_D55.getCode()));
        List<Terminal21> terminal21List = terminal21Mapper.selectByExample(terminal21Example);
        if (CollectionUtil.isEmpty(terminal21List)) {
            payTransaction.setChannelId(ChannelIdEnums.yxy_dy_d40.getCode());
        } else {
            payTransaction.setChannelId(terminal21List.get(0).getChannelId());
        }
        payTransaction.setPlatNo(PlatNoEnums.YXY.getCode());
        payTransaction.setIsDel(false);
        if (StringUtils.equals("VIPPAY", dyTransactionVO.getTXN_CD())) {
            payTransaction.setTransType(LklTransTypeEnum.TYPE_412001.getTransType());
            try {
                //检查channelId 是否相同
                Merchant21 merchant21 = merchantYxyApiService.getMerchant21ByMerchantNo(payTransaction.getMerchantNo());
                if (Objects.nonNull(merchant21) && CollectionUtil.isNotEmpty(terminal21List) && !merchant21.getChannelId().equals(terminal21List.get(0).getChannelId())) {
                    KLog.info("电银商户更正机具channelId 兼容40商户激活50机器 {}，{}", merchant21, terminal21List.get(0));
                    rpcYxyTerminalService.changeTerminalPolicySeries(terminal21List.get(0).getTerminalId(), ChannelIdEnums.isYxy40Product(merchant21.getChannelId()) ?
                            PolicyEnum.PolicySeries.SERIES_40.getCode() : PolicyEnum.PolicySeries.SERIES_50.getCode());
                }
            } catch (Exception e) {
                KLog.warn("矫正channelId失败,{},{}", payTransaction, terminal21List, e);
            }
        } else {
            try {
                payTransaction.setRate(payTransaction.getTransactionFee().divide(payTransaction.getTransactionAmount(),
                        4, BigDecimal.ROUND_HALF_UP)
                        .multiply(new BigDecimal("10000")).intValue());
            } catch (Exception e) {
                KLog.warn("电银交易计算费率错误",e);
            }
        }
        //分润标识
        payTransaction.setProfitFlag(checkIsProfitFlagDy(payTransaction));

        return payTransaction;
    }

    /**
     * 电银判断交易状态
     * @param respCode
     * @return
     */
    private Short formatTradeStatus(String respCode) {
        if (StringUtils.equals(respCode, "S")) {
            return PayTransactionEnum.TransactionStatus.STATUS_10.getCode();
        }
        return PayTransactionEnum.TransactionStatus.STATUS_20.getCode();
    }

    /**
     * 电银判断交易卡类型
     * @param crdFlg
     * @param txnCd
     * @return
     */
    private String formatCardFlagDy(String crdFlg,String txnCd) {
       /**
        * txnCd字段
        * VIPPAY:激活交易
        * ALIPAY:支付宝被扫  MAINALIPAY:支付宝主扫
        * WXPAY:微信被扫
        * MAINWXPAY:微信主扫
        * UNIONCODE:银联二维码
        * MAINUNIONCODE 银联二维码主扫
        * CARDPAY: POS消费
        * crdFlg字段
        * 借记卡
        * 贷记卡
        */
        if (StringUtils.equalsAny(txnCd, "ALIPAY","MAINALIPAY")) {
            return PayTransactionEnum.CardFlagEnum.ALIPAY.getCode();
        }
        if (StringUtils.equalsAny(txnCd, "WXPAY","MAINWXPAY")) {
            return PayTransactionEnum.CardFlagEnum.WECHAT.getCode();
        }
        if (StringUtils.equalsAny(txnCd, "UNIONCODE","MAINUNIONCODE")) {
            return PayTransactionEnum.CardFlagEnum.UNIONCODE.getCode();
        }

        if (StringUtils.equals(crdFlg, "贷记卡")) {
            return PayTransactionEnum.CardFlagEnum.CREDIT_CARD.getCode();
        }
        if (StringUtils.equals(crdFlg, "借记卡")) {
            return PayTransactionEnum.CardFlagEnum.BORROW_CARD.getCode();
        }
        return txnCd+crdFlg;
    }

    //判断是否计入分润
    private boolean checkIsProfitFlagDy(PayTransaction payTransaction) {

        //贷记卡且非押金交易才计入分润
        if (StringUtils.equalsAny(payTransaction.getCardFlag(), PayTransactionEnum.CardFlagEnum.ALIPAY.getCode(),
                PayTransactionEnum.CardFlagEnum.WECHAT.getCode(),
                PayTransactionEnum.CardFlagEnum.CREDIT_CARD.getCode(),
                PayTransactionEnum.CardFlagEnum.UNIONCODE.getCode()) &&
                !StringUtils.equals(LklTransTypeEnum.TYPE_412001.getTransType(), payTransaction.getTransType())) {
            return true;
        }
        return false;
    }

    @Override
    public JSONObject dyUrlRequest(String uri, Map<String, Object> bodyJson) {
        Map<String, String> typeParam = new HashMap<>(); //payTypeApiService.getPayParams(PayTypeEnum.DIANYIN_D40, PayFromEnum.merchant);
        Map<String, Object> headJson = EncryptHelper.genHeadJson(typeParam.get("orgNo"));
        Map<String, Map<String, Object>> requestMap = new HashMap<String, Map<String, Object>>();

        requestMap.put("head", headJson);
        requestMap.put("body", bodyJson);
        FrontContext frontContext = new FrontContext(requestMap);
        frontContext.setPrivateKey(typeParam.get("YXY_PRI_KEY"));
        frontContext.setPublicKey(typeParam.get("YXY_PUB_KEY"));
        FrontHelper frontHelper = new FrontHelper();
        //加密敏感数据
        frontHelper.encryptionData(frontContext);
        frontHelper.signOrgNo(frontContext);
        FrontJsonResponse frontJsonResponse = new FrontJsonResponse();
        frontJsonResponse.setHead(frontContext.getHeadJson());
        frontJsonResponse.setBody(frontContext.getBodyJson());

        KLog.info("加签后请求体:{}", JSON.toJSONString(frontJsonResponse));
        String host = typeParam.get("host");
        HttpResult result = null;
        int requestTime = 3*60 * 1000;
        if (!Objects.isNull(acmTransactionParams.getDianyinRequestTime())) {
            requestTime = acmTransactionParams.getDianyinRequestTime();
        }
        try {
            KLog.info("请求电银接口超时时间:{}",requestTime);
            result = HttpHelper.executePost(host + uri, JSON.toJSONString(frontJsonResponse), "UTF-8", requestTime);
            KLog.info("请求电银接口url:{},返回:{}", host + uri, JSON.toJSONString(result));
        } catch (Exception e) {
            e.printStackTrace();
            KLog.error("请求电银接口失败", e);
        }
        if (!result.getStatusCode().equals(200)) {
            KLog.warn("请求电银接口失败", JSON.toJSONString(result));
            throw new UserBizException(BizCodeMessages.VALIDATOR_ERR, "请求电银接口失败");
        }
        return JSONObject.parseObject(result.getContent());
    }

    @Override
    public JSONObject dyUrlRequestByPayType(String uri, Map<String, Object> bodyJson,PayTypeEnum payTypeEnum) {
        Map<String, String> typeParam = payTypeApiService.getPayParams(payTypeEnum, PayFromEnum.merchant);
        Map<String, Object> headJson = EncryptHelper.genHeadJson(typeParam.get("orgNo"));
        Map<String, Map<String, Object>> requestMap = new HashMap<String, Map<String, Object>>();

        requestMap.put("head", headJson);
        requestMap.put("body", bodyJson);
        FrontContext frontContext = new FrontContext(requestMap);
        frontContext.setPrivateKey(typeParam.get("YXY_PRI_KEY"));
        frontContext.setPublicKey(typeParam.get("YXY_PUB_KEY"));
        FrontHelper frontHelper = new FrontHelper();
        //加密敏感数据
        frontHelper.encryptionData(frontContext);
        frontHelper.signOrgNo(frontContext);
        FrontJsonResponse frontJsonResponse = new FrontJsonResponse();
        frontJsonResponse.setHead(frontContext.getHeadJson());
        frontJsonResponse.setBody(frontContext.getBodyJson());

        KLog.info("加签后请求体:{}", JSON.toJSONString(frontJsonResponse));
        String host = typeParam.get("host");
        HttpResult result = null;
        int requestTime = 3*60 * 1000;
        if (!Objects.isNull(acmTransactionParams.getDianyinRequestTime())) {
            requestTime = acmTransactionParams.getDianyinRequestTime();
        }
        try {
            KLog.info("请求电银接口超时时间:{}",requestTime);
            result = HttpHelper.executePost(host + uri, JSON.toJSONString(frontJsonResponse), "UTF-8", requestTime);
            KLog.info("请求电银接口url:{},返回:{}", host + uri, JSON.toJSONString(result));
        } catch (Exception e) {
            e.printStackTrace();
            KLog.error("请求电银接口失败", e);
        }
        if (!result.getStatusCode().equals(200)) {
            KLog.warn("请求电银接口失败", JSON.toJSONString(result));
            throw new UserBizException(BizCodeMessages.VALIDATOR_ERR, "请求电银接口失败");
        }
        return JSONObject.parseObject(result.getContent());
    }

}
